package cn.fanyc.action.blockchain.fbc.contract.api.impl;

import cn.fanyc.action.blockchain.fbc.contract.api.State;
import cn.fanyc.action.blockchain.fbc.contract.api.StateDeserializer;
import cn.fanyc.action.blockchain.fbc.contract.api.StateList;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.shim.ledger.CompositeKey;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据列表管理实现
 *
 * @author Fanyc
 * @date 2020-10-19 16:46
 */
public class StateListImpl implements StateList {

    /**
     * 合约上下文
     */
    private Context ctx;

    /**
     * 数据列表名称
     */
    private String name;

    /**
     * 数据对象反序列化器
     */
    private StateDeserializer deserializer;

    /**
     * 构造函数
     *
     * @param ctx          合约上下文
     * @param name         数据列表名称
     * @param deserializer 数据对象反序列化器
     */
    public StateListImpl(Context ctx, String name, StateDeserializer deserializer) {
        this.ctx = ctx;
        this.name = name;
        this.deserializer = deserializer;
    }

    /**
     * 添加数据对象
     *
     * @param state 数据对象
     * @return 新的数据对象列表
     */
    @Override
    public StateList addState(State state) {
        System.out.println("adding state name : " + this.name);
        System.out.println("adding state value: " + new JSONObject(state).toString());

        // 构造上链key对象
        CompositeKey compositeKey = this.createCompositeKey(state.getKey());
        System.out.println("ledgerkey is " + compositeKey);

        // 将上链数据对象序列化
        byte[] data = state.serialize();
        // 将对象上链
        this.ctx.getStub().putState(compositeKey.toString(), data);

        // 获取Key集合
        List<Object> keys = new ArrayList<>();
        String stringState = this.ctx.getStub().getStringState(name);
        if (stringState != null && stringState.trim().length() > 0) {
            JSONArray array = new JSONArray(stringState);
            keys = array.toList();
        }
        keys.add(state.getKey());

        this.ctx.getStub().putStringState(name, new JSONArray(keys).toString());

        return this;
    }

    /**
     * 获取数据对象
     *
     * @param key 唯一key
     * @return 数据对象
     */
    @Override
    public State getState(String key) {
        // 构造上链key对象
        CompositeKey compositeKey = this.createCompositeKey(key);
        byte[] data = this.ctx.getStub().getState(compositeKey.toString());
        if (data != null) {
            return this.deserializer.deserialize(data);
        }
        return null;
    }

    /**
     * 更新数据对象
     *
     * @param state 数据对象
     * @return 更新后的对象列表
     */
    @Override
    public StateList updateState(State state) {
        System.out.println("update state value: " + new JSONObject(state).toString());
        CompositeKey compositeKey = this.createCompositeKey(state.getKey());
        byte[] data = state.serialize();
        this.ctx.getStub().putState(compositeKey.toString(), data);
        return this;
    }

    /**
     * 所有Key集合
     *
     * @return Key列表
     */
    @Override
    public List<Object> getKeys() {
        List<Object> keys = new ArrayList<>();
        String stringState = this.ctx.getStub().getStringState(name);
        System.out.println("StateImpl: getKeys = " + stringState);
        if (stringState != null && stringState.trim().length() > 0) {
            JSONArray array = new JSONArray(stringState);
            keys = array.toList();
        }
        return keys;
    }

    /**
     * 构造混合复合KEY
     *
     * @param key 传入的key
     * @return 构造后的上链Key
     */
    private CompositeKey createCompositeKey(String key) {
        System.out.println("createCompositeKey value: " + key);
        return this.ctx.getStub().createCompositeKey(this.name, State.splitKey(key));
    }
}
